<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="LKeFh" id="LKeFh"><span data-lake-id="u5e11b8b4" id="u5e11b8b4">典型回答</span></h1>
  <p data-lake-id="ue656791a" id="ue656791a"><br></p>
  <p data-lake-id="u466479e9" id="u466479e9"><span data-lake-id="u7cf35ae3" id="u7cf35ae3">接口（Interface）和抽象类（Abstract Class）是面向对象编程中两个非常重要的概念，它们都可以用来实现抽象层。</span></p>
  <p data-lake-id="uf4f83ac1" id="uf4f83ac1"><span data-lake-id="uafa530f1" id="uafa530f1">​</span><br></p>
  <p data-lake-id="u48b6a12d" id="u48b6a12d"><span data-lake-id="u4d0e0bf2" id="u4d0e0bf2">接口：</span></p>
  <pre lang="java"><code>
public interface PayService {
    public void pay(PayRequest payRequest);
}
</code></pre>
  <p data-lake-id="u05d516be" id="u05d516be"><br></p>
  <p data-lake-id="u272759c7" id="u272759c7"><span data-lake-id="u420144cf" id="u420144cf">抽象类：</span></p>
  <pre lang="java"><code>
public abstract class AbstractPayService implements PayService {

    @Override
    public void pay(PayRequest payRequest) {
      	//前置检查
        validateRequest(payRequest);
      	//支付核心逻辑
        doPay(payRequest);
      	//后置处理
        postPay(payRequest);
    }

    public abstract void doPay(PayRequest payRequest);

    private void postPay(PayRequest payRequest) {
        //支付成功的后置处理
    }

    public void validateRequest(PayRequest payRequest) {
        //参数检查
    }
}
</code></pre>
  <p data-lake-id="ubb968c7d" id="ubb968c7d"><br></p>
  <p data-lake-id="u465ff992" id="u465ff992"><span data-lake-id="uacbc64b5" id="uacbc64b5">接口和抽象类的区别其实挺多的。比如以下这些：</span></p>
  <p data-lake-id="u3acfbb77" id="u3acfbb77"><span data-lake-id="u0258c2e7" id="u0258c2e7">​</span><br></p>
  <p data-lake-id="u9313a895" id="u9313a895"><strong><span data-lake-id="ueb0bfc8f" id="ueb0bfc8f">方法定义：</span></strong><span data-lake-id="u3614ecc7" id="u3614ecc7">接口和抽象类，最明显的区别就是接口只是定义了一些方法而已，在不考虑Java8中default方法情况下，接口中只有抽象方法，是没有实现的代码的。（Java8中可以有默认方法）</span></p>
  <p data-lake-id="ud4ff59c3" id="ud4ff59c3"><span data-lake-id="u4c09310c" id="u4c09310c">​</span><br></p>
  <p data-lake-id="u9b967466" id="u9b967466"><strong><span data-lake-id="u0edde7b1" id="u0edde7b1">修饰符</span></strong><span data-lake-id="u14b3a999" id="u14b3a999">：抽象类中的抽象方法可以有public、protected和private和&lt;defaiult&gt;这些修饰符，而接口中默认修饰符是public。不可以使用其它修饰符。（接口中，如果定义了成员变量，还必须要初始化）</span></p>
  <p data-lake-id="uba37ef6d" id="uba37ef6d"><span data-lake-id="u8abf7d69" id="u8abf7d69">​</span><br></p>
  <pre lang="java"><code>
public abstract class Test {
    public String a;

    private String b;

    String c;

    protected String d;
}



</code></pre>
  <p data-lake-id="uc3fdb803" id="uc3fdb803"><span data-lake-id="u452cf3b8" id="u452cf3b8">​</span><br></p>
  <p data-lake-id="u3b393415" id="u3b393415" style="text-align: left"><strong><span data-lake-id="ue3db1830" id="ue3db1830">构造器</span></strong><span data-lake-id="u3c7f75ca" id="u3c7f75ca">：抽象类可以有构造器。接口不能有构造器。</span></p>
  <p data-lake-id="ufa96e812" id="ufa96e812" style="text-align: left"><span data-lake-id="ubd95861d" id="ubd95861d">​</span><br></p>
  <blockquote data-lake-id="uaebb149b" id="uaebb149b">
   <p data-lake-id="u3ae5ee15" id="u3ae5ee15" style="text-align: left"><span data-lake-id="uda9f9f10" id="uda9f9f10">抽象类不能直接被实例化（new)出来，但是构造器也是有意义的，能起到初始化共有成员变量、强制初始化操作等作用。</span></p>
  </blockquote>
  <p data-lake-id="u00914871" id="u00914871" style="text-align: left"><span data-lake-id="ub731ec02" id="ub731ec02">​</span><br></p>
  <p data-lake-id="ubdbf3d7e" id="ubdbf3d7e"><strong><span data-lake-id="u8dd395c1" id="u8dd395c1">继承和实现</span></strong><span data-lake-id="u049af65a" id="u049af65a">：接口可以被实现，抽象类可以被继承。</span></p>
  <p data-lake-id="uc4163a3e" id="uc4163a3e"><span data-lake-id="u708b2583" id="u708b2583">​</span><br></p>
  <p data-lake-id="u0d2beb2b" id="u0d2beb2b"><strong><span data-lake-id="u61a17d46" id="u61a17d46">单继承，多实现</span></strong><span data-lake-id="u478ad530" id="u478ad530">：一个类可以实现多个接口，但只能继承一个抽象类。接口支持多重继承，即一个接口可以继承多个其他接口。</span></p>
  <p data-lake-id="ub0b36f2e" id="ub0b36f2e"><span data-lake-id="u65fcba49" id="u65fcba49">​</span><br></p>
  <pre lang="java"><code>
public interface HollisTestService extends InitializingBean, DisposableBean {}
</code></pre>
  <p data-lake-id="ude380d3d" id="ude380d3d"><span data-lake-id="u83f9f233" id="u83f9f233">​</span><br></p>
  <p data-lake-id="u4f631743" id="u4f631743"><strong><span data-lake-id="u07ddb042" id="u07ddb042" style="color: #DF2A3F">职责不同</span></strong><span data-lake-id="u35b01911" id="u35b01911">：接口和抽象类的职责不一样。</span><strong><span data-lake-id="uebd1419b" id="uebd1419b">接口主要用于制定规范</span></strong><span data-lake-id="u71348cc0" id="u71348cc0">，因为我们提倡也经常使用的都是面向接口编程。</span><strong><span data-lake-id="u0e83d591" id="u0e83d591">而抽象类主要目的是为了复用</span></strong><span data-lake-id="ubbab9cf4" id="ubbab9cf4">，比较典型的就是模板方法模式。</span></p>
  <p data-lake-id="u3f5b98e1" id="u3f5b98e1"><span data-lake-id="u1999c4a7" id="u1999c4a7">​</span><br></p>
  <p data-lake-id="udbad8fdf" id="udbad8fdf"><strong><span data-lake-id="u8b36a99f" id="u8b36a99f" style="color: #ED740C">所以当我们想要定义标准、规范的时候，就使用接口。当我们想要复用代码的时候，就使用抽象类。</span></strong></p>
  <p data-lake-id="u6768d7e3" id="u6768d7e3"><span data-lake-id="uccbdf5d5" id="uccbdf5d5">​</span><br></p>
  <p data-lake-id="u9821c28d" id="u9821c28d"><span data-lake-id="uc3e13645" id="uc3e13645">一般在实际开发中，我们会先把接口暴露给外部，然后在业务代码中实现接口。如果多个实现类中有相同可复用的代码，则在接口和实现类中间加一层抽象类，将公用部分代码抽出到抽象类中。可以参考下模板方法模式，这是一个很好的理解接口、抽象类和实现类之间关系的设计模式。</span></p>
  <p data-lake-id="u72d74433" id="u72d74433"><span data-lake-id="ua19e4568" id="ua19e4568">​</span><br></p>
 </body>
</html>